package com.quantum.lang
{
	import flash.utils.getQualifiedClassName;

	public class Enum
	{
		public function get name():String
		{
			return _name;
		}

		public function set name(value:String):void
		{
			this._name=value;
		}

		public function get index():int
		{
			return _index;
		}

		public function toString():String
		{
			return name;
		}

		public static function getEnumConstants(type:Class):Array
		{
			var constants:EnumConstants=_enumDb[getQualifiedClassName(type)];
			if (constants == null)
				return null;
			return constants.byIndex.slice();
		}

		public static function get(i_type:Class, i_constantName:String, i_caseSensitive:Boolean=false):Enum
		{
			var constants:EnumConstants=_enumDb[getQualifiedClassName(i_type)];
			if (constants == null)
				return null;

			var constant:Enum=constants.byName[i_constantName.toLowerCase()];
			if (i_caseSensitive && (constant != null) && (i_constantName != constant.name))
				return null;

			return constant;
		}

		function Enum()
		{
			var typeName:String=getQualifiedClassName(this);
			if (_enumDb[typeName] != null)
			{
				return;
			}

			var constants:Array=_pendingDb[typeName];
			if (constants == null)
				_pendingDb[typeName]=constants=[];

			_index=constants.length;
			constants.push(this);
		}

		protected static function initEnum(i_type:Class):void
		{
			var typeName:String=getQualifiedClassName(i_type);

			if (_enumDb[typeName] != null)
			{
				return;
			}
			var constants:Array=_pendingDb[typeName];
			if (constants == null)
			{
				return;
			}

			// process constants
			var type:XML=flash.utils.describeType(i_type);
			for each (var constant:XML in type.constant)
			{
				// this will fail to coerce if the type isn't inherited from Enum
				var enumConstant:Enum=i_type[constant.@name];

				var enumConstantType:*=Object(enumConstant).constructor;
				if (enumConstantType != i_type)
				{
					throw new Error("Constant type '" + enumConstantType + "' " + "does not match its enum class '" + i_type + "'");
				}

				enumConstant._name=constant.@name;
			}

			// now seal it
			_pendingDb[typeName]=null;
			_enumDb[typeName]=new EnumConstants(constants);
		}

		private var _name:String=null;
		private var _index:int=-1;

		private static var _pendingDb:Object={}; // typename -> [constants]
		private static var _enumDb:Object={}; // typename -> EnumConstants
	}
}